package com.apes.fn.business.insurance.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.business.insurance.modle.InsuranceDiscountsReport;
import com.apes.fn.business.insurance.modle.InsuranceReport;
import com.apes.fn.business.insurance.repository.InsuranceDiscountsReportDao;
import com.apes.fn.business.insurance.repository.InsuranceDiscountsReportRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.hr.base.model.Employee;
import com.apes.hr.base.model.WorkPost;
import com.apes.hr.base.repository.EmployeeRepository;
import com.apes.hr.base.repository.WorkPostRepository;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.finance.service.CrossICService;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.BranchRepository;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.PostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: apes-server
 * @description
 * @author: czs
 * @create: 2021-09-02 16:18
 **/
@Service("insuranceDiscountsReportService")
public class InsuranceDiscountsReportService extends DomainService {

    @Autowired
    InsuranceDiscountsReportDao insuranceDiscountsReportDao;

    @Autowired
    InsuranceDiscountsReportRepository insuranceDiscountsReportRepository;

    @Autowired
    PartyRoleRepository partyRoleRepository;

    @Autowired
    EmployeeRepository employeeRepository;

    @Autowired
    PostRepository postRepository;

    @Autowired
    DeptRepository deptRepository;

    @Autowired
    EnumerationRepository enumerationRepository;

    @Autowired
    BranchRepository branchRepository;

    public JSONObject findAllByDept(SimpleRequest request){
        Map condition = parseCondition(request);
        condition.put("_showType","1");
        return findAll(condition,request);
    }

    public JSONObject findAllBySalesman(SimpleRequest request){
        Map condition = parseCondition(request);
        condition.put("_showType","0");
        return findAll(condition,request);
    }

    public JSONObject findAll(Map condition,SimpleRequest request){
        Date start = (Date) condition.get("CALCULATE_DATE_START");
        Date end = (Date) condition.get("CALCULATE_DATE_END");
        String dateShowType = (String) condition.get("dateShowType");
        String showType = (String) condition.get("_showType");
        Object salesman = condition.get("salesman");
        Object workPost = condition.get("workPost");
        Post one = postRepository.findOne(getPostId(request));
        Dept dept = one.getDept();
        JSONArray deptList = new JSONArray();
        if (dept!=null)deptList.add(dept.getId());
        if (condition.get("dept") == null&&dept!=null)condition.put("dept",deptList);

        if (showType.equals("1")){
            salesman=null;
            workPost=null;
        }
        List<InsuranceDiscountsReport> reports = insuranceDiscountsReportRepository.findAll(
                JpaDsl.toCriteriaIgnoreNull(
                        "dept.id", "IN", condition.get("dept"),
                        "salesman.id", "IN", salesman,
                        "operation.id", "EQ", condition.get("operation"),
                        "post.id", "IN", workPost,
                        "statisticType", "EQ", showType.equals("1")?"dept":"salesman",
                        "statisticDate", "GTE", start,
                        "statisticDate", "LTE", end
                ));
        Map<String, List<InsuranceDiscountsReport>> stringListMap = grounp(reports, showType, dateShowType);
        JSONArray jsonArray = returnToWeb(stringListMap,dateShowType);
        String[] sumFiledList = {"qtyOrder","priceDate","maintainOrder","maintainPrice","tireOrder",
        "tirePrice","maintainPlusOrder","maintainPlusPrice","tirePlusOrder","tirePlusPrice","orderMonth","priceMonth"};
        return getSumPage(request.getJO(),jsonArray,sumFiledList);
    }

    /**
     * 手动分页+汇总
     * @param jo
     * @param jsonArray
     * @param sumFiledList
     * @return
     */
    public JSONObject getSumPage(JSONObject jo,JSONArray jsonArray,String[] sumFiledList){
        JSONObject result = new JSONObject();
        JSONObject footer = new JSONObject();
        JSONArray footers = new JSONArray();
        footer.put("SYS_RID",1);
        //汇总
        double sumValue = 0;
        for (String s : sumFiledList) {
            for (Object v : jsonArray) {
                JSONObject vJson = (JSONObject)v;
                if (vJson.getDouble(s)==null)throw new RuntimeException("分组字段有误,请检查字段'"+s+"'");
                sumValue+=vJson.getDouble(s);
            }
            Math.round(sumValue);
            footer.put(s,sumValue);
            sumValue=0;
        }

        footers.add(footer);
        result.put("footer",footers);
        result.put("content",jsonArray);
        result.put("elements",jsonArray.size());
        result.put("page",(Integer) jo.get("page"));
        result.put("pages",jsonArray.size()/(Integer) jo.get("size"));
        result.put("size",(Integer) jo.get("size"));
        result.put("total",jsonArray.size());
        return result;


    }

    private JSONArray returnToWeb(Map<String, List<InsuranceDiscountsReport>> stringListMap,String dateShowType) {
        JSONArray resultList = new JSONArray();
        for (String s : stringListMap.keySet()) {
            List<InsuranceDiscountsReport> insuranceDiscountsReports = stringListMap.get(s);
            InsuranceDiscountsReport report = insuranceDiscountsReports.stream().sorted(Comparator.comparing(InsuranceDiscountsReport::getStatistic).reversed().reversed()).findFirst().get();
            JSONObject reusltJson = new JSONObject();
            String date = "month".equals(dateShowType) ? DateUtil.format(report.getStatisticDateMonth(), DateUtil.SHOW_MONTH_FORMAT) : DateUtil.format(report.getStatisticDate(), DateUtil.SHOW_DATE_FORMAT);
            Date sortDate = "month".equals(dateShowType) ? report.getStatisticDateMonth() : report.getStatisticDate();
            reusltJson.put("statisticDate",date);
            reusltJson.put("sortDate",sortDate);
            mergeReportData(insuranceDiscountsReports,reusltJson,report);
            resultList.add(reusltJson);

        }
        resultList = resultList.stream().sorted(Comparator.comparing(result -> ((JSONObject)result).getDate("sortDate")).reversed()).collect(Collectors.toCollection(JSONArray::new));
        return resultList;
    }

    private void mergeReportData(List<InsuranceDiscountsReport> insuranceDiscountsReports, JSONObject reusltJson, InsuranceDiscountsReport report) {
        double priceDate = 0;
        double qtyOrder = 0;
        double maintainOrder = 0;
        double maintainPrice = 0;
        double maintainPlusOrder = 0;
        double maintainPlusPrice = 0;
        double tireOrder = 0;
        double tirePrice = 0;
        double tirePlusOrder = 0;
        double tirePlusPrice = 0;
        double priceConcurrentMonth = 0;
        double qtyConcurrentMonthOrder = 0;
        double priceConcurrentYear = 0;
        double qtyConcurrentYearOrder = 0;

        for (InsuranceDiscountsReport v : insuranceDiscountsReports) {
            priceDate+=v.getPriceDate();
            qtyOrder += v.getQtyOrder();
            maintainOrder += v.getMaintainOrder();
            maintainPrice += v.getMaintainPrice();
            maintainPlusOrder += v.getMaintainPlusOrder();
            maintainPlusPrice += v.getMaintainPlusPrice();
            tireOrder += v.getTireOrder();
            tirePrice += v.getTirePrice();
            tirePlusOrder += v.getTirePlusOrder();
            tirePlusPrice += v.getTirePlusPrice();
            priceConcurrentMonth += v.getPriceConcurrentMonth();
            qtyConcurrentMonthOrder += v.getQtyConcurrentMonthOrder();
            priceConcurrentYear += v.getPriceConcurrentYear();
            qtyConcurrentYearOrder += v.getQtyConcurrentYearOrder();
        }


        reusltJson.put("salesman",report.getSalesman()==null?null:report.getSalesman().getName());
        reusltJson.put("post",report.getPost()==null?null:report.getPost().getName());
        reusltJson.put("dept",report.getDept()==null?report.getBranch().getName():report.getDept().getName());
        reusltJson.put("operation",report.getOperation()==null?null:report.getOperation().getDescription());
        reusltJson.put("priceDate",priceDate);
        reusltJson.put("qtyOrder",qtyOrder);
        reusltJson.put("maintainOrder",maintainOrder);
        reusltJson.put("maintainPrice",maintainPrice);
        reusltJson.put("maintainPlusOrder",maintainPlusOrder);
        reusltJson.put("maintainPlusPrice",maintainPlusPrice);
        reusltJson.put("tireOrder",tireOrder);
        reusltJson.put("tirePrice",tirePrice);
        reusltJson.put("tirePlusOrder",tirePlusOrder);
        reusltJson.put("tirePlusPrice",tirePlusPrice);
        reusltJson.put("orderMonth",report.getQtyMonthOrder());
        reusltJson.put("priceMonth",report.getPriceMonth());
        reusltJson.put("priceConcurrentMonth",priceConcurrentMonth);
        reusltJson.put("qtyConcurrentMonthOrder",qtyConcurrentMonthOrder);
        reusltJson.put("priceConcurrentYear",priceConcurrentYear);
        reusltJson.put("qtyConcurrentYearOrder",qtyConcurrentYearOrder);
        reusltJson.put("orderHB",qtyConcurrentMonthOrder==0?"100%":Math.round(((qtyOrder-qtyConcurrentMonthOrder)/qtyConcurrentMonthOrder)*100)+"%");
        reusltJson.put("priceHB",priceConcurrentMonth==0?"100%":Math.round(((priceDate-priceConcurrentMonth)/priceConcurrentMonth)*100)+"%");
        reusltJson.put("orderTB",qtyConcurrentYearOrder==0?"100%":Math.round(((qtyOrder-qtyConcurrentYearOrder)/qtyConcurrentYearOrder)*100)+"%");
        reusltJson.put("priceTB",priceConcurrentYear==0?"100%":Math.round(((priceDate-priceConcurrentYear)/priceConcurrentYear)*100)+"%");
    }

    /**
     * 分组
     * @param reports
     * @param showType
     * @param dateShowType
     * @return
     */
    private Map<String, List<InsuranceDiscountsReport>> grounp(List<InsuranceDiscountsReport> reports,String showType,String dateShowType){
        Map<String, List<InsuranceDiscountsReport>> collect = null ;
        if (dateShowType.equals("month")){
            if (showType.equals("1")){
                collect = reports.stream().collect(Collectors.groupingBy(report -> report.getStatisticDateMonth()+(report.getDept()==null?report.getBranch().getId():report.getDept().getId())));
            }else {
                collect = reports.stream().collect(Collectors.groupingBy(report -> report.getStatisticDateMonth()+report.getSalesman().getId()+(report.getDept()==null?report.getBranch().getId():report.getDept().getId())));
            }
        }else if (dateShowType.equals("date")){
            if (showType.equals("1")){
                collect = reports.stream().collect(Collectors.groupingBy(report -> report.getStatisticDate()+(report.getDept()==null?report.getBranch().getId():report.getDept().getId())));
            }else {
                collect = reports.stream().collect(Collectors.groupingBy(report -> report.getStatisticDate()+report.getSalesman().getId()+(report.getDept()==null?report.getBranch().getId():report.getDept().getId())));
            }
        }
        if (collect==null)throw new RuntimeException("分组不存在");
        return collect;
    }


    /***
     * 解析条件
     */
    private Map parseCondition(SimpleRequest request) {
        JSONArray condition = request.getJO().getJSONArray("condition");
        Map returnMap = new HashMap();
        condition.stream().forEach(json -> {
            JSONObject obj = (JSONObject) json;

            if (obj.getString("type") == null) {
                returnMap.put(obj.getString("field"), obj.getString("value"));
                if (obj.getString("operator")!=null&&obj.getString("operator").equals("IN")) {
                    JSONArray value = obj.getJSONArray("value");

                    returnMap.put(obj.getString("field"),value);
                }
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("GTE")) {
                returnMap.put(obj.getString("field") + "_START", DateUtil.parse(obj.getString("value"), DateUtil.SHOW_DATETIME_FORMAT));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("LTE")) {
                returnMap.put(obj.getString("field") + "_END", DateUtil.parse(obj.getString("value"), DateUtil.SHOW_DATETIME_FORMAT));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("EQ")) {
                returnMap.put(obj.getString("field"), DateUtil.parse(obj.getString("value")));
            }
        });
        return returnMap;
    }


    public String insuranceDiscountsDailySettlement(SimpleRequest request){
        JSONObject jo = request.getJO();
        Date date = jo.getDate("date") == null ? new Date() : jo.getDate("date");
        JSONObject param = new JSONObject();
        String format = DateUtil.format(date, DateUtil.SHOW_DATE_FORMAT);
        Date satrt = DateUtil.parse(format, DateUtil.SHOW_DATE_FORMAT);
        param.put("start",satrt);
        param.put("end",date);
        List<InsuranceDiscountsReport> all = insuranceDiscountsReportRepository.findAll(
                JpaDsl.toCriteriaIgnoreNull(
                        "statisticDate", "GTE", satrt,
                        "statisticDate", "LTE", satrt
                ));
        if (all.size() > 0){
            all.stream().forEach(v->{
                insuranceDiscountsReportRepository.delete(v.getId());
            });
        }
        JSONArray eMaintain = insuranceDiscountsReportDao.findEMaintain(param);
        groupingSave(eMaintain);
        return "1";
    }

    /**
     * 分组保存
     * @param eMaintain
     */
    private void groupingSave(JSONArray eMaintain){
        //两个维度保存
        //一.人员
        Map<String, List<Object>> salesman = eMaintain.stream().collect(Collectors.groupingBy(v-> ((JSONObject) v).getString("SALESMAN")+((JSONObject) v).getString("DEPT")));
        //二.门店
        Map<String, List<Object>> dept = eMaintain.stream().collect(Collectors.groupingBy(v-> ((JSONObject) v).getString("DEPT")+"1"));
        dailySettlement(salesman,"SALESMAN");
        dailySettlement(dept,"DEPT");
    }

    private void dailySettlement(Map<String, List<Object>> collect,String type){
        for (String s : collect.keySet()) {
            List<Object> reports = collect.get(s);
            reports.stream().forEach(v->{
                JSONObject reportJson = (JSONObject) v;
                InsuranceDiscountsReport report = new InsuranceDiscountsReport();
                if ("SALESMAN".equals(type)){
                    report.setSalesman(partyRoleRepository.findOne(reportJson.getString("SALESMAN")));
                    if (reportJson.getString("POST")!=null)report.setPost(employeeRepository.findOne(reportJson.getString("POST")).getPost());
                    report.setStatisticType("salesman");
                }else {
                    report.setStatisticType("dept");
                }
                if (reportJson.getString("DEPT")!=null){
                    Dept dept = deptRepository.findOne(reportJson.getString("DEPT"));
                    if (dept!=null){
                        report.setDept(dept);
                    }else {
                        report.setBranch(branchRepository.findOne(reportJson.getString("DEPT")));
                    }
                }
                if (reportJson.getString("OPERATION")!=null)report.setOperation(enumerationRepository.findOne(reportJson.getString("OPERATION")));
                report.setStatisticDate(reportJson.getDate("STATISTICS_DATE"));
                report.setPriceDate(reportJson.getDoubleValue("DATE_PRICE"));
                report.setQtyOrder(reportJson.getInteger("DATE_ORDERS"));
                report.setMaintainOrder(reportJson.getInteger("MAINTAIN_ORDER"));
                report.setMaintainPrice(reportJson.getDoubleValue("MAINTAIN_PRICE"));
                report.setMaintainPlusOrder(reportJson.getInteger("MAINTAIN_PLUS_ORDER"));
                report.setMaintainPlusPrice(reportJson.getDoubleValue("MAINTAIN_PLUS_PRICE"));
                report.setTireOrder(reportJson.getDoubleValue("TIRE_ORDER"));
                report.setTirePrice(reportJson.getDoubleValue("TIRE_PRICE"));
                report.setTirePlusOrder(reportJson.getDoubleValue("TIRE_PLUS_ORDER"));
                report.setTirePlusPrice(reportJson.getDoubleValue("TIRE_PLUS_PRICE"));
                report.setPriceMonth(reportJson.getDoubleValue("MOTH_RECEIPT_PRICE"));
                report.setQtyMonthOrder(reportJson.getInteger("MOTH_RECEIPT_ORDER"));
                report.setPriceConcurrentMonth(reportJson.getDoubleValue("LAST_MOTH_RECEIPT_PRICE"));
                report.setQtyConcurrentMonthOrder(reportJson.getInteger("LAST_MOTH_RECEIPT_ORDER"));
                report.setPriceConcurrentYear(reportJson.getDoubleValue("LAST_YEAR_RECEIPT_ORDER"));
                report.setQtyConcurrentYearOrder(reportJson.getInteger("LAST_YEAR_RECEIPT_PRICE"));
                insuranceDiscountsReportRepository.save(report);
            });
        }
    }

    /**
     * 测试日结
     * @param request
     * @return
     */
    public String insuranceDailySettlementTest(SimpleRequest request){
        JSONObject jo = request.getJO();
        String date = jo.getString("date");
        if (date==null)return "date不能为空";
//        Date start = DateUtil.parse(date, DateUtil.SHOW_DATE_FORMAT);
//        return this.invoke("fn.insurance.insuranceDiscountsDailySettlement", MapUtil.mapper("date", start));
        Date endDate = new Date();
        long nowTime = endDate.getTime();
        int day = 0;
        int exception = 0;
        List exceptionList = new ArrayList();
        Date startTemp = DateUtil.parse(date, DateUtil.SHOW_DATE_FORMAT);
        Date start = DateUtil.parse(DateUtil.timeStampToStr(startTemp.getTime()), DateUtil.SHOW_DATE_FORMAT);
        String msg ="";
        do {
            try{
                String date1 = this.invoke("fn.insurance.insuranceDiscountsDailySettlement", MapUtil.mapper("date", start));

                if (date1.contains("已日结,请勿重复日结"))return "完成"+day+"天,报错数量:"+exception;
            }catch (Exception e){
                exception++;
                String format = DateUtil.format(start, DateUtil.SHOW_DATE_FORMAT);
                exceptionList.add(format);
                msg= e.getMessage();
            }
            long time = start.getTime()+86400000L;
            start = new Date(time);
            day++;
        }while (nowTime >start.getTime());
        StringBuffer sf = new StringBuffer();
        exceptionList.forEach(v->{
            sf.append(v+",");
        });


        return "完成"+day+"天,报错数量:"+exception+"报错天数:"+sf.toString()+" 原因:"+msg;
    }


}
